﻿using Exelus.Win11DesktopSwitchAnimatior;
using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DesktopSwipeAnimationIsBack
{
    public class SwipeSimulator
    {
        private PointerTouchInfo[] touches = new PointerTouchInfo[0];


        private static Lazy<object> initializer = new Lazy<object>(() => { TouchInjector.InitializeTouchInjection(10,TouchFeedback.DEFAULT) ; return new object(); });

        public SwipeSimulator() {
            initializer.Value.ToString();
            touches = new PointerTouchInfo[4];
            for (int i = 0; i < 4; i++)
            {
                var touch = new PointerTouchInfo()
                {
                    PointerInfo = new PointerInfo()
                    {
                        PtPixelLocation = new TouchPoint()
                        {
                            X = 200,
                            Y = (i * 50) + 50,
                        },
                        pointerType = PointerInputType.TOUCH,
                        PointerFlags = PointerFlags.DOWN | PointerFlags.INRANGE | PointerFlags.INCONTACT,
                        PointerId = (uint)i,
                    },
                    Orientation = 90,
                    Pressure = 32000,
                    TouchMasks = TouchMask.CONTACTAREA | TouchMask.ORIENTATION | TouchMask.PRESSURE
                };
                touches[i] = (touch);
            }
        }

        public void Aquire()
        {
            usesTouch = 4;
            var displayW = Screen.PrimaryScreen.Bounds.Width;
            var displayH = Screen.PrimaryScreen.Bounds.Height;
            for (pointerIndex = 0; pointerIndex < touches.Length; pointerIndex++)
            {
                touches[pointerIndex].PointerInfo.PointerId = (uint)pointerIndex;
            }
            var begin = displayW / 2;
            startX = begin;
            maxDelta =  displayW / 24;
            triggleThrehold1 = displayW / 8;
            triggleThrehold2 = displayW / 8 * 7 ;
            contactstate = -4;
            MoveTo(begin);
            PressDown();
            Apply();
        }

        public void Release() {
            PressUp();
            if(contactstate == 0)
            {
                Apply(0);
            }
            else
            {
                Apply();

            }
        }


        int contactstate = 0; // <=0: 初始状态，所有手指按下，0: 新增手指按下，1：抬起旧的手指
        int usesTouch = 0;
        int maxDelta = 0;
        int triggleThrehold1 = 0;
        int triggleThrehold2 = 0;
        int startX;
        int pointerIndex = 0;
        


        public void Move(int delta)
        {
            
            var rawDelta = delta;
            if(delta < -maxDelta)
            {
                delta = -maxDelta;
            }
            if(delta  > maxDelta)
            {
                delta = maxDelta;
            }
            int curX = touches[0].PointerInfo.PtPixelLocation.X;
            //Console.WriteLine($"X={curX}, Delta={delta} / {rawDelta}, usesTouch={usesTouch}, contactState={contactstate}, threhold={triggleThrehold1},{triggleThrehold2}");
            

            if (contactstate < 0)
            {

                if (curX < triggleThrehold1 * 2 || curX > triggleThrehold1 * 6)
                {
                    if (contactstate < -1)
                    {
                        contactstate++;
                    }

                }
                if (contactstate == -1)
                {
                    touches[1].PointerInfo.PointerFlags = PointerFlags.UP;
                    touches[2].PointerInfo.PointerFlags = PointerFlags.UP;
                    touches[3].PointerInfo.PointerFlags = PointerFlags.UP;
                    Apply(0,1,2,3);
                    MoveBy(delta);
                    Apply(0);
                    contactstate = 0;
                }
                else
                {

                    MoveBy(delta);
                    Apply(0,1,2,3);
                }

            }
            else
            {
                MoveBy(delta);
                Apply(0);

                if (curX < triggleThrehold1 || curX > triggleThrehold2)
                {
                    touches[1].PointerInfo.PointerFlags = PointerFlags.DOWN | PointerFlags.INRANGE | PointerFlags.INCONTACT;
                    touches[1].PointerInfo.PtPixelLocation.X = startX;
                    touches[1].PointerInfo.PointerId = (uint)++pointerIndex;
                    if(pointerIndex >= 8)
                    {
                        pointerIndex = 0;
                    }

                    Thread.Sleep(3);
                    Application.DoEvents();
                    Apply(0,1);

                    swapFingers();
                    touches[0].PointerInfo.PointerFlags = PointerFlags.UPDATE | PointerFlags.INRANGE | PointerFlags.INCONTACT;
                    touches[1].PointerInfo.PointerFlags = PointerFlags.UP;
                    Thread.Sleep(3);
                    Application.DoEvents();
                    Apply(1,0);

                }
            }

        }

        private void swapFingers()
        {
            var cache = touches[0];
            touches[0] = touches[1];
            touches[1] = cache;
        }



        private void PressDown()
        {
            for (int i = 0; i < 4; i++)
            {
                touches[i].PointerInfo.PointerFlags = PointerFlags.DOWN | PointerFlags.INRANGE | PointerFlags.INCONTACT;
            }
        }

        private void MoveTo(int x)
        {
            for (int i = 0; i < 4; i++)
            {
                touches[i].PointerInfo.PtPixelLocation.X =x;
                touches[i].PointerInfo.PointerFlags = PointerFlags.UPDATE | PointerFlags.INRANGE | PointerFlags.INCONTACT;
            }
        }
        private void MoveBy(int x)
        {
            for (int i = 0; i < 4; i++)
            {
                touches[i].PointerInfo.PtPixelLocation.X += x;
                touches[i].PointerInfo.PointerFlags = PointerFlags.UPDATE | PointerFlags.INRANGE | PointerFlags.INCONTACT;
            }
        }

        private void PressUp()
        {
            for (int i = 0; i < 4; i++)
            {
                touches[i].PointerInfo.PointerFlags = PointerFlags.UP;
            }
        }
        private void Apply(params int[] which)
        {
            PointerTouchInfo[] pointerTouches = new PointerTouchInfo[which.Length];
            for (int i = 0;i < which.Length; i++)
            {
                pointerTouches[i] = touches[which[i]];
            }
            if(!TouchInjector.InjectTouchInput(which.Length, pointerTouches))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Invalid state!");
                Console.ResetColor();
            }
        }
        private void Apply()
        {
            if(!TouchInjector.InjectTouchInput(4, touches))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Invalid state!");
                Console.ResetColor();
            }
        }
    }
}
